/*
   Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
   Original sources are available at www.latestbit.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   SimpleInterfaceTesters.hpp. Created on: 28.09.2010 15:59:32 
*/


#ifndef SIMPLEINTERFACETESTERS_HPP_
#define SIMPLEINTERFACETESTERS_HPP_

#include <cpputils/TestUtils.hpp>
#include <smartobjects/SmartBus.hpp>
#include <org_latestbit_smartobjects_testmodel.hpp>


using namespace smartobjects;
using namespace testmodel;

class SimpleSyncSmartObjectImpl : public ISimpleInterfaceSyncSmartObject {
public:
	inline SimpleSyncSmartObjectImpl() {
	}

	inline virtual ~SimpleSyncSmartObjectImpl() {
	}

	inline virtual std::string  helloWorld(const std::string& name   )
    throw(IOException, SmartBusSystemException) {
		return "Hello "+name;
	};

    inline virtual std::string  helloWorld2(const std::string& name ,  ISimpleStructure* firstStructure   )
    throw(IOException, SmartBusSystemException) { return "Hello "+name; };

    inline virtual ISimpleStructure*  helloWorld3(const std::string& name , ISimpleStructure* firstStructure   )
    throw(IOException, SmartBusSystemException) { firstStructure->addRef(); firstStructure->setStrVal( firstStructure->getStrVal()+" "+name); return firstStructure; };

    inline virtual std::string  helloWorld4(const std::string& name   )
    throw(IOException, SmartBusSystemException , SimpleException) { return "Hello "+name; };

    inline virtual std::string  helloWorldEncrypted(const std::string& name   )
    throw(IOException, SmartBusSystemException) { return "Hello "+name; };

    inline virtual void  manualDestroy() throw(IOException, SmartBusSystemException) {
    	ServerSkeleton::getCurrentRequestContext()->getSkeleton()->unpublish();
    };
};

class SimpleInterfaceCallbackImpl : public ISimpleInterfaceCallback {
public:
	inline SimpleInterfaceCallbackImpl() : m_poCurrentStructure(NULL) {

	}

	inline virtual ~SimpleInterfaceCallbackImpl() {
		releaseAndClear(m_poCurrentStructure);
	}

	inline virtual void onHelloWorldResponse(const std::string& ,  RefObject* userObject) {
    	;
    }

    inline virtual void onHelloWorld2Response(const std::string& ,  RefObject* userObject) {

    }

    inline virtual void onHelloWorld3Response(ISimpleStructure* param,  RefObject* userObject)  {
    	boost::recursive_mutex::scoped_lock oLock(m_mxMonitor);
    	setNewRefObject( m_poCurrentStructure, param );
    	notifyWaiter();
    }

    inline virtual void onHelloWorld4Response(const std::string& ,  RefObject* userObject) {

    }

    inline virtual void onHelloWorld4Response(const SimpleException& ex, RefObject* userObject) {

    }

    inline virtual void onHelloWorldEncryptedResponse(const std::string& ,  RefObject* userObject) {

    }

    inline virtual void onManualDestroyResponse(RefObject* userObject) {

    }

	inline virtual void onResponseTimeout (
					const std::string& sOperationId,
					RefObject* poUserObject )
						throw() {
    	notifyWaiter();
	}

	inline virtual void onResponseSystemException (
					const std::string& sOperationId,
					const SmartBusSystemException& oex,
					RefObject* poUserObject )
						throw() {
    	notifyWaiter();
	}


	inline boost::recursive_mutex& getMonitor() {
		return m_mxMonitor;
	}

	inline void waitForAnyEvent(boost::recursive_mutex::scoped_lock& oLock, const std::string& sLocation="Unknown location") {
		if(!m_evAwait.timed_wait(oLock,boost::posix_time::seconds(3))) {
			std::cout << "Timeout for waiting accept event! Location: " << sLocation <<std::endl;
			throw SystemException("Timeout for waiting accept event! Location: " + sLocation);
		}
	}

	inline ISimpleStructure* getCurrentStructure() {
		return m_poCurrentStructure;
	}

	inline void resetCurrentStructure() {
		releaseAndClear(m_poCurrentStructure);
	}

protected:
	inline void notifyWaiter() {
		boost::recursive_mutex::scoped_lock oLock(m_mxMonitor);
		m_evAwait.notify_one();
	}


protected:
	boost::condition m_evAwait;
	boost::recursive_mutex m_mxMonitor;
	ISimpleStructure* m_poCurrentStructure;

};

class SimpleSyncFactoryServer : public ISimpleFactorySyncSmartObject {
    inline virtual ~SimpleSyncFactoryServer() {}

    inline virtual SimpleInterfaceSkeleton*  createSimpleInterface() throw(IOException, SmartBusSystemException) {
    	boost::intrusive_ptr < SimpleSyncSmartObjectImpl > impl ( new SimpleSyncSmartObjectImpl(), false );
    	SimpleInterfaceSkeleton* skeleton = new SimpleInterfaceSyncSkeleton(impl.get());
    	return skeleton;
    }

    inline virtual std::string  putSimpleInterface(ISimpleInterface* intf   ) throw(IOException, SmartBusSystemException) {
    	const std::string result = intf->helloWorld("John");
    	intf->manualDestroy();
    	return result;
    }

    inline virtual std::string  createSimpleSession() throw(IOException, SmartBusSystemException) {
    	return "myid";
    }

    inline virtual void  continueSession(const std::string& id   ) throw(IOException, SmartBusSystemException) {
    	if( id != "myid")
    		throw SmartBusSystemException("ID is not match!");
    }
};

#endif /* SIMPLEINTERFACETESTERS_HPP_ */
